/**

 * @author admin

 * 2014年7月15日

 */

package com.tmall.testgen.client.runinspring;

import java.io.BufferedInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.tmall.testgen.client.ClientDataCenter;
import com.tmall.testgen.client.config.ConfigUtil;
import com.tmall.testgen.client.genfile.genproject.ProjectGenerator;
import com.tmall.testgen.client.runinspring.push.TestGenMain;
import com.tmall.testgen.client.runinspring.push.jmx.Compute;
import com.tmall.testgen.client.runinspring.push.jmx.ComputeMBean;
import com.tmall.testgen.client.runinspring.push.jmx.ComputeResult;
import com.tmall.testgen.client.runinspring.push.jmx.DBInfoForJmx;
import com.tmall.testgen.client.runinspring.push.jmx.InitApplicationContextResult;
import com.tmall.testgen.client.socket.SocketClient;
import com.tmall.testgen.common.bo.interact.back.DBInfo;
import com.tmall.testgen.common.bo.interact.back.InterceptInfo;
import com.tmall.testgen.common.bo.interact.back.syn.BaseInfo;
import com.tmall.testgen.common.util.StringUtil;
import com.tmall.testgen.plugin.views.vo.SpringTree;
import com.tmall.testgen.transfer.client.TransferClient;

public class RunInSpringHandler {
	
	private static URLClassLoader classLoader;
	private volatile boolean isSpringStart=false;
	
	private  ComputeMBean computeService;
	private static XStream xstream = new XStream(new DomDriver  ());
	
	private static RunInSpringHandler instance=new RunInSpringHandler();
	
	public static RunInSpringHandler getInstance(){
		return instance;
	}
	
	public  void clear(){
		new Thread(new Runnable(){

			@Override
			public void run() {
				try{
				    cancelStart();
				}catch(Exception e){
				    e.printStackTrace();
				}
			}
			
		}).start();
		
		isSpringStart=false;
	}
	
	
	private void handleJar(String projectName,String targetProject,boolean isUseHsf ) throws Exception{
		 // 获取工作区
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
       
        IProject project = root.getProject(projectName);
        IJavaProject javaProject=  JavaCore.create(project);
        
		List<String> jars=new ArrayList<String>();
		if(isUseHsf){
			jars.add("hsf.app.spring-1.4.9.jar");
			jars.add("hsf.lib-1.4.9.jar");
			jars.add("hsf.services-1.4.9.jar");
			jars.add("hsfunit-1.0.5-SNAPSHOT.jar");
			jars.add("dbunit-2.4.4.jar");
		}
		jars.add("xpp3-1.1.4c.jar");
		jars.add("xstream-1.4.7.jar");
		jars.add("push.jar");
		jars.add("javax.servlet-api-3.0.1.jar");
		
		for(String jar:jars){
			createJar(javaProject, jar);
		}
		
		// 得到旧的build path
        IClasspathEntry[] oldClasspathEntries = javaProject.readRawClasspath();
        Map<String,IClasspathEntry> jarPathMap=new LinkedHashMap<String,IClasspathEntry>();
		
		
		for(String jar:jars){
			String fpath=javaProject.getPath().toString()+"/lib/"+jar;
			jarPathMap.put(fpath, JavaCore.newLibraryEntry(new Path(fpath), null, null));
		}
        
		if(oldClasspathEntries!=null){
			for(IClasspathEntry entry:oldClasspathEntries){
				jarPathMap.put(entry.getPath().toString(), entry);
			}
		}
		 List <IClasspathEntry> list = new ArrayList<IClasspathEntry>();
        for(String path:jarPathMap.keySet()){
        	list.add(jarPathMap.get(path));
        }
	        
	     javaProject.setRawClasspath(list.toArray(new IClasspathEntry[list.size()]), null);
	}
	public void cancelStart(){
	    try{
	        SocketClient.getInstance().closeSocket();
	    }catch(Exception e){
	         //   e.printStackTrace();
	     }
	    try{
	        computeService.stopService();
        }catch(Exception e){
              //  e.printStackTrace();
         }
	    try{
	        connector.close();
        }catch(Exception e){
             //   e.printStackTrace();
         }
           
           
        
	}
	public void changeConfigLoacation(String projectName,String targetProject,String config) throws Exception{
	    cancelStart();
		classLoader=ConfigUtil.getClassLoader(projectName);
		targetProject=StringUtil.normalizePath(targetProject);
		//String targetProjectName=targetProject.substring(targetProject.lastIndexOf("/")+1);
		
		
		handleJar(projectName,targetProject,ClientDataCenter.getInstance().getIsUseHsf());
		
		
		AutoConfigReplacer.handleAutoConfig(ConfigUtil.getRefProjectOutputs(projectName, true));
		
		LaunchMainClass.launch(projectName, TestGenMain.class.getName());
		
		int tryCount=0;
		while(!initService()&&tryCount<3){
			Thread.sleep(1000);
			tryCount++;
		}
		InitApplicationContextResult initResult=null;
		try{
			initResult=computeService.initApplicationContext(config,ClientDataCenter.getInstance().getIsUseHsf(),ClientDataCenter.getInstance().getHsfConfig());
			ClientDataCenter.getInstance().setPid(initResult.getPid());
		}catch(Exception e){
			e.printStackTrace();
		}
		if(!initResult.isSucc()){
			throw new Exception("启动失败...");
		}
		
		List<DBInfo> dbInfoes=new ArrayList<DBInfo>();
		
		if(initResult.getDbInfoes()!=null){
			for(DBInfoForJmx info:initResult.getDbInfoes()){
				DBInfo i=new DBInfo();
				i.setDriverClass(info.getDriverClass());
				i.setPassword(info.getPassword());
				i.setUrl(info.getUrl());
				i.setUserName(info.getUserName());
				dbInfoes.add(i);
			}
		}
		this.isSpringStart=true;
		ClientDataCenter.getInstance().setDbInfos(dbInfoes);
		
	}
	
	private JMXConnector connector;
	public boolean initService() throws Exception{
		try{
			 Map<String, String[]> props = new HashMap<String, String[]>();  
		    JMXServiceURL address =  
		      new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9874/jmxrmi");  
		     connector = JMXConnectorFactory.connect(address, props);  
		    MBeanServerConnection  mbsc = connector.getMBeanServerConnection();  
	
		    connector.connect();  
	
		    ObjectName objectName=new ObjectName("compute:name=compute");  
		    if(!mbsc.isRegistered(objectName)){  
		        mbsc.createMBean(Compute.class.getName(), objectName,null,null);  
		    }  
	
		    computeService = JMX.newMBeanProxy(mbsc, objectName,   ComputeMBean.class);  
		}catch(Exception e){
		    //e.printStackTrace();
			return false;
		}
		return true;
		
	}
	
	
	/**
	 * 获取执行结果
	 * @param method
	 * @param root
	 * @return
	 * @throws Throwable 
	 */
	public InterceptInfo getResult(final Method method,String methodShowName,SpringTree root) throws Exception{
		
		
		InterceptInfo info=null;
		try {
			Object[] params=new Object[root.getChildren().length];
			for(int i=0;i<root.getChildren().length;i++){
				params[i]=RunInSpringUtil.getValue((SpringTree) root.getChildren()[i]);
			}
			
			info=this.getInterceptInfo(  method, methodShowName, params);
			
			
			xstream.setClassLoader(method.getDeclaringClass().getClassLoader());
			final String[] paramStrs=new String[params.length];
			if(params!=null){
				for(int i=0;i<paramStrs.length;i++){
					paramStrs[i]=xstream.toXML(params[i]);
				}
			}
//			FrameworkDebugOptions dbgOptions = FrameworkDebugOptions.getDefault();
//			dbgOptions.isDebugEnabled()
			
			
			ComputeResult  computeResult=computeService.compute(method.getDeclaringClass().getName(), method.getName(), method.getParameterTypes(),paramStrs);
			if(computeResult==null)
			    info.setException("获取执行结果失败,请查看控制台检查异常!");
			else{
			    info.setBeanName(computeResult.getBeanName());
	            //
	            info.setResult(xstream.fromXML(computeResult.getResult()));
			}
			
			
			
			return info;
		} catch (Exception e) {
			if(e instanceof InvocationTargetException){
				Throwable t= ((InvocationTargetException)e).getTargetException();
				if(t instanceof Exception){
					throw (Exception)t;
				}
			}else
				throw e;
		}
		return null;
	}
	
	private InterceptInfo getInterceptInfo(Method method,String methodShowName,Object[] params){
		InterceptInfo info=new InterceptInfo();
		info.setClassName(method.getDeclaringClass().getName());
		info.setClassSimpleName(method.getDeclaringClass().getSimpleName());
		info.setMethodName(method.getName());
		
		methodShowName=StringUtil.formatMethod(methodShowName);
		int pos=methodShowName.indexOf("(");
		info.setMethodParamContent(methodShowName.substring(pos));
		
		List<String > paramNames=new ArrayList<String>();
		String content=info.getMethodParamContent().substring(1, info.getMethodParamContent().lastIndexOf(")"));
		if(content.length()>0){
			String[] paramPair=content.split(",");
			for(String pn:paramPair){
				paramNames.add(pn.split(" ")[1]);
			}
			
		}	
		
		info.setParamNames(paramNames);
		List l=new ArrayList();
		for(Object param:params){
			l.add(param);
		}
		info.setParams(l);
		info.setType(BaseInfo.TYPE_INTERCEPT);
		return info;
	}

	public static void createJar(IJavaProject javaProject,String jarFileName) throws Exception{
        IFolder rootFolder = javaProject.getProject().getFolder(new Path("/lib"));
         if(!rootFolder.exists())
             rootFolder.create(true, true, null);
         
         
        IFile currentFile =rootFolder.getFile(jarFileName); 
        if(currentFile.exists())
            return;
        
         BufferedInputStream inBuff = new BufferedInputStream(ProjectGenerator.class.getResourceAsStream("/lib/"+jarFileName));
         currentFile.create(inBuff, false, null) ;
         
    }
	public static URLClassLoader getClassLoader() {
		return classLoader;
	}

    public boolean isSpringStart() {
        return isSpringStart;
    }

    public void setSpringStart(boolean isSpringStart) {
        this.isSpringStart = isSpringStart;
    }
	

}
